package com.king.collect;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Lists;

/**
 * @author taomk
 * @version 1.0
 * @since 15-1-31 下午5:52
 */
public class ImmutableTest {

	/**
	 * 不可变集合，顾名思义就是说集合是不可被修改的。集合的数据项是在创建的时候提供，并且在整个生命周期中都不可改变。
	 * 为什么要用immutable对象？immutable对象有以下的优点：
	 * 1. 对不可靠的客户代码库来说，它使用安全，可以在未受信任的类库中安全的使用这些对象。
	 * 2. 线程安全的：immutable对象在多线程下安全，没有竞态条件。
	 * 3. 不需要支持可变性, 可以尽量节省空间和时间的开销. 所有的不可变集合实现都比可变集合更加有效的利用内存 (analysis)。
	 * 4. 可以被使用为一个常量，并且期望在未来也是保持不变的。
	 * @param args
	 */
	public static void main(String [] args) {
		testJDKImmutable();
		testGuavaImmutable();
	}

	/**
	 * JDK的Collections.unmodifiableXXX方法实现不可变集合的一些问题：
	 * 1. 它用起来笨拙繁琐你不得不在每个防御性编程拷贝的地方用这个方法。
	 * 2. 它不安全：如果有对象reference原始的被封装的集合类，这些方法返回的集合也就不是正真的不可改变。
	 * 3. 效率低：因为它返回的数据结构本质仍旧是原来的集合类，所以它的操作开销，包括并发下修改检查，hash table里的额外数据空间都和原来的集合是一样的。
	 */
	public static void testJDKImmutable() {
		List<String> list=new ArrayList<>();
		list.add("a");
		list.add("b");
		list.add("c");

		System.out.println(list);

		// Collections.unmodifiableList实现的不是真正的不可变集合，当原始集合修改后，不可变集合也发生变化。
		List<String> unmodifiableList= Collections.unmodifiableList(list);

		System.out.println(unmodifiableList);

		List<String> unmodifiableList1=Collections.unmodifiableList(Arrays.asList("a", "b", "c"));
		System.out.println(unmodifiableList1);

		String temp=unmodifiableList.get(1);
		System.out.println("unmodifiableList [0]："+temp);

		list.add("baby");
		System.out.println("list add a item after list:"+list);
		System.out.println("list add a item after unmodifiableList:"+unmodifiableList);

		// 不可变集合不可以修改集合数据，当强制修改时会报错，实例中的最后两个add会直接抛出不可修改的错误。
		unmodifiableList1.add("bb");
		System.out.println("unmodifiableList add a item after list:"+unmodifiableList1);

		unmodifiableList.add("cc");
		System.out.println("unmodifiableList add a item after list:"+unmodifiableList);
	}

	/**
	 * 注意：每个Guava immutable集合类的实现都拒绝null值。我们做过对Google内部代码的全面的调查，并且发现只有5%的情况下集合类允许null值，而95%的情况下都拒绝null值。万一你真的需要能接受null值的集合类，你可以考虑用Collections.unmodifiableXXX。
	 */
	public static void testGuavaImmutable() {
		List<String> list= Lists.newArrayList();
		list.add("a");
		list.add("b");
		list.add("c");
		System.out.println("list："+list);

		ImmutableList<String> imlist=ImmutableList.copyOf(list);
		System.out.println("imlist："+imlist);

		ImmutableList<String> imOflist=ImmutableList.of("peida","jerry","harry");
		System.out.println("imOflist："+imOflist);

		ImmutableSortedSet<String> imSortList=ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
		System.out.println("imSortList："+imSortList);

		list.add("baby");
		System.out.println("list add a item after list:"+list);
		System.out.println("list add a item after imlist:"+imlist);
	}


}
